﻿using System.Collections.Concurrent;
using System.Net;

namespace GCC.Container.Abstracts
{
    /// <summary>
    /// 通信服务抽象基类
    /// </summary>    
    /// <remarks>
    /// 制作自定义实现的方法:
    /// 你需要确定你得协议头多长,flag多长,当然你可以没有flag,只有协议头,你只需要把flagSize赋值为0即可
    /// 重写checkheader,checkflag,来重写原本的默认实现    
    /// 处理数据如果代码非要传递,请记得拷贝
    /// 默认实现中,Flag:0x55 0xaa,head:是int32
    /// 调用时序时:flagcheck->headCheck->handleData
    /// </remarks>
    public abstract class AbsCommUDPServer<T> : AbsCommServer, IDisposable
    {
        /// <summary>
        /// 是否已经销毁
        /// </summary>
        protected bool _disposed;

        /// <summary>
        /// 日志对象
        /// </summary>
        protected readonly AbsGCCLogger _logger;

        /// <summary>
        /// 当获取到数据时事件
        /// </summary>
        public event Action<AbsCommUDPClient<T>>? GotClient;

        /// <summary>
        /// 原始套接字对象
        /// </summary>
        protected readonly AbsCommUDPClient<T> _server;

        /// <summary>
        /// 绑定地址
        /// </summary>
        protected readonly IPEndPoint _ipEndPoint;
        /// <summary>
        /// 是否再运行中
        /// </summary>
        protected bool _started;

        /// <summary>
        /// 取消token
        /// </summary>
        protected readonly CancellationTokenSource _cancellToken = new();

        /// <summary>
        /// 目标客户端池
        /// </summary>
        protected readonly ConcurrentDictionary<IPEndPoint, AbsCommUDPClient<T>> _targetPool = new();

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="iPEndPoint">目标绑定地址</param>
        /// <param name="logger">日志</param>
        /// <param name="name">名称</param>
        protected AbsCommUDPServer(IPEndPoint iPEndPoint, AbsGCCLogger logger, string name)
        {
            Name = name;
            ServerType = "UDP";
            _ipEndPoint = iPEndPoint;
            _logger = logger;
            _server = GetServer(name, iPEndPoint);
            _server.GotInternalData += _server_GotData;
        }

        /// <summary>
        /// When the server got new message
        /// </summary>
        /// <param name="data">data info</param>
        /// <param name="target">remove info</param>
        /// <exception cref="NotImplementedException"></exception>
        private void _server_GotData(T data, IPEndPoint target)
        {
            var targetClient = _targetPool.GetOrAdd(target, (t) =>
              {
                  var tempClient = GetServerClient($"{target}_UDP_Client_{Guid.NewGuid():N}", t);
                  tempClient.TrySend += TargetClient_TrySend;
                  tempClient.OnDisposing += TargetClient_OnDisposing;
                  GotClient?.Invoke(tempClient);
                  return tempClient;
              });
            targetClient.TriggerDataEvent(data);
        }
        /// <summary>
        /// 取消事件钩子
        /// </summary>
        /// <param name="obj"></param>
        private void TargetClient_OnDisposing(IPEndPoint? obj)
        {
            if (obj is null)
            {
                return;
            }
            if (_targetPool.Remove(obj, out var instance))
            {
                instance.TrySend -= TargetClient_TrySend;
                instance.OnDisposing -= TargetClient_OnDisposing;
            }
        }

        private bool TargetClient_TrySend(Memory<byte> arg, IPEndPoint target)
        {
            return _server.SendRawData(arg, target);
        }

        /// <summary>
        /// 启动服务
        /// </summary>
        public void Start()
        {
            if (!_started)
            {
                lock (this)
                {
                    if (!_started)
                    {
                        _server.StartReceive();
                        _started = true;
                    }
                }
            }
        }

        /// <summary>
        /// 析构函数
        /// </summary>
        ~AbsCommUDPServer()
        {
            Dispose(false);
        }

        /// <summary>
        /// 销毁模型
        /// </summary>
        /// <param name="flag">是否是用户主动调用</param>
        protected virtual void Dispose(bool flag)
        {
            if (_disposed)
            {
                return;
            }
            _disposed = true;
            _server.Dispose();

        }

        /// <summary>
        /// 销毁模型
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }


        /// <summary>
        /// 获取一个当前服务的客户端
        /// </summary>
        /// <param name="name">名称</param>
        /// <param name="localInfo">本地地址信息</param>
        /// <returns></returns>
        protected abstract AbsCommUDPClient<T> GetServer(string name, IPEndPoint localInfo);
        /// <summary>
        /// 获取一个服务器专用客户端
        /// </summary>
        /// <param name="name">名称</param>
        /// <param name="target">目标端</param>
        /// <returns></returns>
        protected abstract AbsCommUDPClient<T> GetServerClient(string name, IPEndPoint target);

        /// <summary>
        /// 获取一个客户端
        /// </summary>
        /// <param name="name">名称</param>
        /// <param name="localEndPoint">本地端不填写则随机生成</param>
        /// <returns></returns>
        public abstract AbsCommUDPClient<T> GetClient(string name, IPEndPoint? localEndPoint = null);

    }
}
